import { Uri, ViewColumn, window, workspace } from 'vscode';
import { TemplatePreview } from '@ibizlab/template';
import { pathExistsSync, readFileSync } from 'fs-extra';
import * as yaml from 'js-yaml';
import { GlobalConst } from './constants';
import { ctx } from './global';
import { PreviewConfig } from './interface';
import { normalize, sep } from 'path';
import { winToUnixPath } from './utils';

/**
 * 预览适配器
 *
 * @author chitanda
 * @date 2022-01-17 11:01:59
 * @export
 * @class PreviewManager
 */
export class PreviewManager {
  /**
   * 预览程序缓存，基于模型和模板目录
   *
   * @author chitanda
   * @date 2022-01-19 11:01:18
   * @protected
   * @type {Map<string, any>}
   */
  protected previewCache: Map<string, any> = new Map();
  /**
   * 已经预览过的模板文件路径缓存，方便保存以后自动刷新
   *
   * @author chitanda
   * @date 2022-02-10 16:02:49
   * @protected
   * @type {Map<string, string>}
   */
  protected previewPathCache: Map<string, string> = new Map();

  /**
   * Creates an instance of PreviewManager.
   *
   * @author chitanda
   * @date 2022-02-10 16:02:14
   */
  constructor() {
    workspace.onDidSaveTextDocument(e => {
      if (this.previewPathCache.has(e.uri.path)) {
        this.preview(e.uri);
      }
    });
  }

  /**
   * 预览指定文件
   *
   * @author chitanda
   * @date 2022-01-18 18:01:13
   * @param {Uri} uri
   */
  async preview(uri: Uri): Promise<void> {
    const config = this.getConfig(uri);
    const previewKey = `${config.modelFolder}_${config.templateFolder}`;
    let preview: TemplatePreview;
    if (this.previewCache.has(previewKey)) {
      preview = this.previewCache.get(previewKey);
    } else {
      preview = new TemplatePreview(config.modelFolder, config.templateFolder);
      this.previewCache.set(previewKey, preview);
    }
    try {
      const path = uri.fsPath.split(sep).slice(config.templateFolder.split(sep).length).join(sep);
      const data = preview.execute(path, config.modelId);
      if (data) {
        const normalizePath = winToUnixPath(normalize(`${GlobalConst.PREVIEW_SYSTEM_SCHEME}:/${path.replace('.hbs', '')}`));
        const fileUri = Uri.parse(normalizePath);
        const file = ctx.fs.findFile(fileUri);
        const bufferData = Buffer.from(data.content);
        ctx.fs.writeFile(fileUri, bufferData, { create: file ? false : true, overwrite: true });
        this.previewPathCache.set(uri.path, uri.path);
        window.showTextDocument(fileUri, { preview: true, preserveFocus: true, viewColumn: ViewColumn.Two });
      }
    } catch (err: any) {
      window.showErrorMessage(err.message);
    }
  }

  /**
   * 根据已经预览过的文件，再次打开编辑器时重新预览
   *
   * @author chitanda
   * @date 2022-02-10 17:02:12
   * @param {Uri} uri
   * @return {*}  {Promise<boolean>}
   */
  async repreview(uri: Uri): Promise<boolean> {
    const config = this.getConfig(uri);
    const tempPath = winToUnixPath(normalize(`${config.templateFolder}${uri.path}.hbs`));
    const tempUri = Uri.file(tempPath);
    const file = await workspace.fs.stat(tempUri);
    if (file) {
      await this.preview(tempUri);
      return true;
    }
    return false;
  }

  /**
   * 获取预览配置
   *
   * @author chitanda
   * @date 2022-01-18 18:01:43
   * @protected
   * @param {Uri} uri
   * @return {*}  {PreviewConfig}
   */
  protected getConfig(uri: Uri): PreviewConfig {
    if (!ctx.config.modelFolder) {
      throw new Error('请现在工作区中配置模型文件夹');
    }
    const config: PreviewConfig = {
      templateFolder: ctx.config.templateFolder,
      modelFolder: ctx.config.modelFolder,
    };
    const configPath = uri.fsPath.replace('.hbs', '.yaml');
    if (pathExistsSync(configPath)) {
      const content = readFileSync(configPath, 'utf-8');
      const json = yaml.load(content) as Record<string, any>;
      if (json && json.model) {
        const { id, type } = json.model;
        if (id) {
          config.modelId = id;
        }
        if (type) {
          config.modelType = type;
        }
      }
    }
    return config;
  }
}
// 预览管理器
export const manage = new PreviewManager();
